﻿using System;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using NewBusiness.Domain.Uow.Data;


namespace NewBusiness.Domain.Uow.Repositories
{
    public interface IEntity
    {
        int Id { get; set; }
    }

    public interface IRepository<T> where T : class, IEntity
    {
        IQueryable<T> GetAll();
        T GetById<TProperty>(int id, params Expression<Func<T, TProperty>>[] includes);
        T GetById(int id);

        void Create(T entity);
        void Update(T entity);
        void Delete(T entity);
        void Detach(T entity);
    }

    public class Repository<T> : IRepository<T> where T : class, IEntity
    {
        private readonly DataContext _context;
        private readonly DbSet<T> _set;

        public Repository(DataContext context)
        {
            _context = context;
            _set = context.Set<T>();
        }

        public virtual IQueryable<T> GetAll()
        {
            return _set;
        }

        public virtual T GetById<TProperty>(int id, params Expression<Func<T, TProperty>>[] includes)
        {
            var set = _set as IQueryable<T>;
            set = includes.Aggregate(set, (current, include) => current.Include(include));

            Func<T, bool> byId = t => t.Id == id;

            return set.FirstOrDefault(byId);
        }

        public virtual T GetById(int id)
        {
            var set = _set as IQueryable<T>;
            Func<T, bool> byId = t => t.Id == id;
            return set.FirstOrDefault(byId);
        }

        public void Detach(T entity)
        {
            _context.Entry(entity).State = EntityState.Detached;
        }

        public virtual void Create(T entity)
        {
            _set.Add(entity);
        }

        public virtual void Update(T entity)
        {
            _context.Entry(entity).State = EntityState.Modified;
        }

        public virtual void Delete(T entity)
        {
            if (_context.Entry(entity).State == EntityState.Detached)
            {
                _context.Entry(entity).State = EntityState.Deleted;
            }
            else
            {
                _set.Remove(entity);
            }
        }
    }
}
